Skip to content

ci: publish releases automatically on a tag push - #5624

Closed
yohimik wants to merge 3 commits into
tinygo-org:devfrom
yohimik:ci/automated-release
Closed

ci: publish releases automatically on a tag push#5624
yohimik wants to merge 3 commits into
tinygo-org:devfrom
yohimik:ci/automated-release

Conversation

@yohimik

@yohimik yohimik commented Aug 28, 2026

Copy link
Copy Markdown

Hello! CI already builds everything a release needs, but publishing is still
manual — download the nine artifacts from the run, create the release, attach
them by hand. This automates that.

What it does. Pushing a v* tag runs the Linux, macOS and Windows
workflows via workflow_call, so what ships is what was tested, then collects
their artifacts into a draft release — draft on purpose, so you still
review the notes and paste in the CHANGELOG entry before publishing.

It checks the tag against goenv/version.go before starting the builds, since
the asset filenames come from that constant rather than from the tag. And it
checks all nine files actually arrived, so a build that quietly stops uploading
can't produce a half-complete release. That check earned its place immediately:
the first run failed on it, because the Windows release is itself a .zip and
download-artifact unpacked it instead of keeping the file.

No checksum file: GitHub records a SHA-256 digest for every asset itself. The
release notes just say how to print them.

Caching. Tag runs no longer save the LLVM caches. Caches are scoped to
the ref that creates them: a tag run can restore from the default branch, but
anything it saves lands in a scope named after that one tag and no later run
can ever read it — not another tag, not the default branch. On my fork the
first release run left 25 entries totalling 2.6 GB stranded that way. Since
eviction is by least recent access, a release that missed the cache could push
out the default-branch entries every other run depends on. Restore is
untouched, which is where the benefit is.

Other changes to the existing workflows are small — a workflow_call
trigger, and their concurrency groups no longer use github.workflow. Inside a
called workflow that context is the caller's, so all three would land in the
same group and cancel each other; the literals evaluate to the same string as
before for pull request and push runs.

Tested end to end on my fork: https://github.com/yohimik/tinygo/actions/runs/33208158272
All 23 jobs green, nine assets on a draft release, and every published asset's
digest matches the digest of the artifact its build job produced. (That run
predates a rebase onto current dev; the change set is identical.)

image

Let me know if anything should change — naming, draft vs. published, the notes
wording, any of it.

yohimik and others added 3 commits August 29, 2026 01:36
The Linux, macOS and Windows workflows already build every file a release
needs, but nothing published them: the artifacts were downloaded from the
Actions run and attached to a hand-made GitHub Release.

Add a Release workflow that runs on a v* tag. It calls the three build
workflows, so everything that ships is also tested in the same run, then
collects their artifacts into a draft release. It first checks the tag against
goenv/version.go, because the release filenames are derived from that constant
rather than from the tag, and it checks all nine files arrived so a build that
stopped uploading cannot produce a half-complete release.

The three build workflows gain a workflow_call trigger. Their concurrency
groups had to stop using github.workflow: inside a called workflow that context
is the caller's, so all three would resolve to the same group and, with
cancel-in-progress, cancel each other and the caller. The literals used instead
evaluate to the same string as before for pull request and push runs.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Caches are scoped to the ref that created them. A run triggered by a tag can
restore caches from the default branch, but anything it saves lands in a scope
named after that one tag, which no later run can ever read: not another tag,
not the default branch.

So on a release run the two LLVM caches are written once and never used again,
while still counting against the repository's 10 GB quota. Since eviction is by
least recent access, a release that missed the cache could push out the
default-branch entries that every other run depends on.

Restore still happens on tag runs, which is where the benefit is. Only the save
is skipped.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The build jobs upload with archive: false, which stores the file as-is rather
than wrapping it in a zip. The Windows release is itself a .zip, so on download
it was detected as an archive and unpacked: dist/ ended up with a tinygo/
directory instead of tinygo<version>.windows-amd64.zip, and the release would
have shipped without a Windows build.

Set skip-decompress so the file is kept as it was uploaded. The unpacking
cannot be turned off at the upload side, because the Windows test jobs download
that same artifact and rely on getting it unpacked.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@deadprogram

Copy link
Copy Markdown
Member

Please follow the guidelines in AGENTS.md thank you,

@deadprogram

Copy link
Copy Markdown
Member

See #5626 for my own attempt to do this, somewhat based on this PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants